package top.haijunit.common.response.advice;

import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import jakarta.validation.ValidationException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import top.haijunit.common.response.data.ExceptionEnum;
import top.haijunit.common.response.data.ExceptionSupport;
import top.haijunit.common.response.data.RestResult;

import java.util.stream.Collectors;

/**
 * 全局异常处理
 *
 * @author zhanghaijun
 * @date 2024/6/6 13:13
 * @description [一句话描述该类的功能]
 */
@Slf4j
@ControllerAdvice
@Order(200)
public class GlobalExceptionAdvice {

    @ResponseBody
    @ExceptionHandler(value = Throwable.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public RestResult<Object> exceptionHandler(Throwable throwable) {
        log.error("全局异常捕获：{}", throwable.getClass().getName(), throwable);
        if (throwable instanceof ExceptionSupport) {
            return RestResult.of(((ExceptionSupport) throwable), null);
        }
        return RestResult.of(500, throwable.getMessage(), null);
    }

    @ExceptionHandler(value = NullPointerException.class)
    @ResponseBody
    public RestResult<Object> exceptionHandler(NullPointerException exception) {
        log.error("发生空指针异常！原因是:", exception);
        return RestResult.of(ExceptionEnum.BODY_NOT_MATCH, null);
    }

    @ExceptionHandler(value = NumberFormatException.class)
    @ResponseBody
    public RestResult<Object> exceptionHandler(NumberFormatException e) {
        log.error("发生类型转换异常！原因是:", e);
        return RestResult.of(ExceptionEnum.PARAMS_NOT_CONVERT, null);
    }

    @ResponseBody
    @ExceptionHandler(value = {BindException.class, ValidationException.class, MethodArgumentNotValidException.class})
    public ResponseEntity<RestResult<String>> handleValidatedException(Exception exception) {
        RestResult<String> resp = null;
        if (exception instanceof MethodArgumentNotValidException ex) {
            resp = RestResult.of(ExceptionEnum.INTERNAL_SERVER_ERROR,
                    ex.getBindingResult().getAllErrors().stream()
                            .map(ObjectError::getDefaultMessage)
                            .collect(Collectors.joining("; "))
            );
        } else if (exception instanceof ConstraintViolationException ex) {
            resp = RestResult.of(ExceptionEnum.INTERNAL_SERVER_ERROR,
                    ex.getConstraintViolations().stream()
                            .map(ConstraintViolation::getMessage)
                            .collect(Collectors.joining("; "))
            );
        } else if (exception instanceof BindException ex) {
            resp = RestResult.of(ExceptionEnum.INTERNAL_SERVER_ERROR,
                    ex.getAllErrors().stream()
                            .map(ObjectError::getDefaultMessage)
                            .collect(Collectors.joining("; "))
            );
        }
        if (resp != null) {
            log.error("参数校验异常:{}", resp.getMessage());
        }
        return new ResponseEntity<>(resp, HttpStatus.BAD_REQUEST);
    }
}
